use std::{fmt::Display, ops::Deref, path::Path, sync::Arc};

use indradb::{MemoryDatastore, RocksdbDatastore};
use rpm::{RPMPackage, RPMPackageMetadata};
use uuid::Uuid;

use crate::{
    cache::{
        parse_rpm::read_metadata_from_rpm_headers,
        parse_xml::{PkgDetailState, XmlState},
        repo_data::RepoData,
    },
    conf::repo_conf::RepoConfig,
};
use anyhow::{bail, Result};
pub struct Repo {
    pub data: RepoData<RocksdbDatastore>,
    pub config: Arc<RepoConfig>,
}
impl Deref for Repo {
    type Target = RepoData<RocksdbDatastore>;

    fn deref(&self) -> &Self::Target {
        &self.data
    }
}
impl Clone for Repo {
    fn clone(&self) -> Self {
        Self {
            data: self.data.clone(),
            config: self.config.clone(),
        }
    }
}
pub struct CmdRepo {
    pub data: RepoData<MemoryDatastore>,
}
impl Clone for CmdRepo {
    fn clone(&self) -> Self {
        Self {
            data: self.data.clone(),
        }
    }
}
impl Deref for CmdRepo {
    type Target = RepoData<MemoryDatastore>;

    fn deref(&self) -> &Self::Target {
        &self.data
    }
}
impl CmdRepo {
    pub async fn new<P: AsRef<Path> + Display>(
        paths: Vec<P>,
    ) -> Result<(Self, Vec<(Uuid, String)>)> {
        let db = Arc::new(MemoryDatastore::new_db());
        db.index_property(PkgDetailState::Name.as_identifier())
            .unwrap();
        db.index_property(XmlState::Entry.as_identifier().unwrap())
            .unwrap();
        let mut headers = Vec::new();
        let mut pkg_infos = Vec::new();
        for path in paths.iter() {
            match RPMPackage::open(path) {
                Ok(rpm) => {
                    let pkg_uuid = get_uuid(&rpm.metadata);
                    let pkg_name = rpm.metadata.get_name().unwrap().to_string();
                    headers.push((pkg_uuid, rpm.metadata.header));
                    pkg_infos.push((pkg_uuid, pkg_name));
                }
                Err(e) => {
                    bail!(
                        "Can't parse rpm file {} to get headers , because {}",
                        path,
                        e
                    )
                }
            };
        }
        read_metadata_from_rpm_headers(db.clone(), 1, headers).await?;
        RepoData::new(&db);
        Ok((
            Self {
                data: RepoData::new(&db),
            },
            pkg_infos,
        ))
    }
}
fn get_uuid(metadata: &RPMPackageMetadata) -> Uuid {
    match metadata.get_md5() {
        Ok(b) => {
            match Uuid::from_slice(b) {
                Ok(s) => {
                    return s;
                }
                Err(_) => {}
            };
        }
        Err(_) => {}
    }
    return *uuid::Builder::from_md5_bytes(md5::compute(&metadata.header).0).as_uuid();
}
#[tokio::test]
async fn test_rpm() {
    // dbg!(CmdRepo::new(vec!["tests/389-ds-base-2.2.3-1.fc37.x86_64.rpm"]).await.unwrap());
    let (cmd_repo, _pkg_uuids) = CmdRepo::new(vec!["tests/389-ds-base-2.2.3-1.fc37.x86_64.rpm"])
        .await
        .unwrap();
    // dbg!(cmd_repo.data.count_pkg().await);
    let _detail = cmd_repo.data.get_pkg_detail_by_name("389-ds-base").await;
    let pkg_uuid = cmd_repo
        .data
        .clone()
        .get_pkg_uuid_by_pkg_name(Arc::new("389-ds-base".to_string()))
        .unwrap();
    let conflicts = cmd_repo.data.get_pkg_conflicts_by_uuid(pkg_uuid).await;
    // dbg!(detail);
    dbg!(conflicts);
}
#[tokio::test]
async fn test_rpma() {
    // dbg!(CmdRepo::new(vec!["tests/389-ds-base-2.2.3-1.fc37.x86_64.rpm"]).await.unwrap());
    let (cmd_repo, _pkg_uuids) = CmdRepo::new(vec!["tests/kdevelop-22.08.1-2.fc37.x86_64.rpm"])
        .await
        .unwrap();
    // dbg!(cmd_repo.data.count_pkg().await);
    let detail = cmd_repo.data.get_pkg_detail_by_name("kdevelop").await;
    dbg!(detail);
    // let pkg_uuid = cmd_repo
    //     .data
    //     .clone()
    //     .get_pkg_uuid_by_pkg_name(Arc::new("389-ds-base".to_string()))
    //     .await
    //     .unwrap();
    // let conflicts = cmd_repo.data.get_pkg_conflicts_by_uuid(pkg_uuid).await;
    // // dbg!(detail);
    // dbg!(conflicts);
}
